﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace modul3
{
    [Serializable]
    public class SysConstr
    {
        #region privatne atributy
        private int piNextConstraintsId = 1;
        private List<SysConstrMy> paData = new List<SysConstrMy>();
        #endregion


        #region properties
        public int iNextConstraintsId
        {
            get { return piNextConstraintsId; }
            set { piNextConstraintsId = value; }
        }

        public List<SysConstrMy> aData
        {
            get { return paData; }
            set { paData = value; }
        }
        #endregion


        #region metody
        public void konzola()
        {
            Console.WriteLine(piNextConstraintsId);
        }

        public kkRetValue CreateCon(string pa_sNazov, SysConstrTypes pa_kTyp, List<int> pa_aZrojoveStlpce, List<int> pa_aReferencovaneStlpce)
        {
            kkRetValue vystup = kkRetValue.OK;
            SysConstrMy novy = new SysConstrMy(pa_sNazov, pa_kTyp, pa_aZrojoveStlpce, pa_aReferencovaneStlpce, iNextConstraintsId);
            if (pa_kTyp == SysConstrTypes.PK)
            {
                if (pa_aReferencovaneStlpce.Count != 0)
                {
                    vystup = kkRetValue.NespravneReferencovaneStlpce;
                }
                else if (pa_aZrojoveStlpce.Count == 0)
                {
                    vystup = kkRetValue.ZiadneZdrojoveStlpce;
                }
                else
                {
                    // kontrola, ze ci nahodou uz PK neexistuje na danej tabulke (PK moze byt len jeden)
                    foreach (SysConstrMy constraint in aData)
                    {
                        if (constraint.kTyp == SysConstrTypes.PK)
                        {
                            // TO DO: kontrola, ci uz existuje v tabulke primatny kluc
                            //if (false)
                            //{
                            //    vystup = kkRetValue.AlreadyExists;
                            //}
                        }
                    }
                }
            }
            else if (pa_kTyp == SysConstrTypes.FK)
            {
                if (pa_aReferencovaneStlpce.Count == 0)
                {
                    vystup = kkRetValue.ZiadneReferencovaneStlpce;
                }
                else if (pa_aZrojoveStlpce.Count == 0)
                {
                    vystup = kkRetValue.ZiadneZdrojoveStlpce;
                }
                else if (pa_aZrojoveStlpce.Count != pa_aReferencovaneStlpce.Count)
                {
                    vystup = kkRetValue.NespravneReferencovaneStlpce;
                }
                else
                {
                    // kontrola, ze ci nahodou uz taky isty FK neexistuje
                    int pocetNajdeniZdroj; // pocet najdenych zdrojovych stlpcov - zhody
                    int pocetNajdeniRef; // pocet najdenych referencovanych stlpcov - zhody
                    foreach (SysConstrMy constraint in aData)
                    {
                        if (constraint.kTyp == SysConstrTypes.FK && constraint.aZdrojeoveStlpce.Count == novy.aZdrojeoveStlpce.Count)
                        {
                            pocetNajdeniZdroj = 0;
                            pocetNajdeniRef = 0;
                            foreach (int column in constraint.aZdrojeoveStlpce)
                            {
                                if (novy.aZdrojeoveStlpce.Contains(column))
                                {
                                    pocetNajdeniZdroj++;
                                }
                            }
                            if (pocetNajdeniZdroj == constraint.aZdrojeoveStlpce.Count)
                            {
                                pocetNajdeniRef = 0;
                                foreach (int column in constraint.aReferencovaneStlpce)
                                {
                                    if (novy.aReferencovaneStlpce.Contains(column))
                                    {
                                        pocetNajdeniRef++;
                                    }
                                }
                            }
                            if (pocetNajdeniRef == constraint.aReferencovaneStlpce.Count)
                            {
                                vystup = kkRetValue.AlreadyExists;
                            }
                        }
                    }
                }
            }
            else
            {
                vystup = kkRetValue.Chyba;
            }

            if (vystup == kkRetValue.OK)
            {
                aData.Add(novy);
                iNextConstraintsId++;
                Save();
            }
            return vystup;
        }

        private kkRetValue DropCon(SysConstrMy pa_cDroppedConstraint)
        {
            kkRetValue vystup;
            if (aData.Remove(pa_cDroppedConstraint))
            {
                vystup = kkRetValue.OK;
                Save();
            }
            else
            {
                vystup = kkRetValue.Nenajdeny;
            }
            return vystup;
        }

        public kkRetValue DropCon(int pa_iDroppedConstraint)
        {
            return DropCon(getObjectFromId(pa_iDroppedConstraint));
        }

        private SysConstrMy getObjectFromId(int pa_iDroppedConstraint)
        {
            foreach (SysConstrMy constrCyklus in aData)
            {
                if (constrCyklus.iId == pa_iDroppedConstraint)
                {
                    return constrCyklus;
                }
            }
            return null;
        }

        public SysConstrTypes TestTyp(int pa_iConstraint)
        {
            SysConstrMy s = getObjectFromId(pa_iConstraint);
            if (s == null)
            {
                return SysConstrTypes.chyba;
            }
            else
            {
                return s.kTyp;
            }
        }

        public List<int> ShowPK(List<int> paStlpceTabulky)
        {
            List<int> vystup = new List<int>();
            foreach (SysConstrMy constraint in paData)
	        {
                if(constraint.kTyp == SysConstrTypes.PK){
                    foreach (int stlpecId in paStlpceTabulky)
	                {
                        if(constraint.aZdrojeoveStlpce.Contains(stlpecId)){
                            vystup.Add(stlpecId);
                        }
	                }
                }
	        }
            return vystup;
        }

        public void Save()
        {
            FunctionsModule3.StoreSysConstr(this);
        }

        /// <summary>
        ///  kontroluje, ci sa na stlpec vztahuje nejake obmedzenie.
        ///  Parameter: id stlpcu.
        ///  Return: 0 pokial neexistuje, id constraintu pokial existuje.
        /// </summary>
        /// <param name="pa_iColumn">id stlpcu</param>
        /// <returns></returns>
        public int columnConstraint(int pa_iColumn)
        {
            foreach (SysConstrMy data in paData)
            {
                foreach (int columnCyklus in data.aReferencovaneStlpce)
                {
                    if (columnCyklus == pa_iColumn)
                    {
                        return data.iId;
                    }
                }

                foreach (int columnCyklus in data.aZdrojeoveStlpce)
                {
                    if (columnCyklus == pa_iColumn)
                    {
                        return data.iId;
                    }
                }
            }
            return 0;
        }

        /// <summary>
        /// dropne vsetky constrainty zo stlpca
        /// </summary>
        public void dropAllFromColumn(int pa_iColumn)
        {
            int constraint;
            while ((constraint = columnConstraint(pa_iColumn)) != 0)
            {
                if (DropCon(constraint) != kkRetValue.OK)
                {
                    // ked sa nepodari vymazat index
                    throw new Exception("chyba");
                }
            }
        }

        /// <summary>
        /// stlpce, ktore ukazuju na referencovany stlpec
        /// </summary>
        public List<int> DajZoznamZdrojovychStlpcov(int paReferencovanyStlpec)
        {
            List<int> vystup = new List<int>();
            foreach (SysConstrMy data in paData)
            {
                for (int i = 0; i < data.aReferencovaneStlpce.Count; i++)
                {
                    if (data.aReferencovaneStlpce[i] == paReferencovanyStlpec)
                    {
                        vystup.Add(data.aZdrojeoveStlpce[i]);
                    }
                }
            }
            return vystup;
        }
        #endregion
    }
}
